package com.cw.lang.common.framework.inteceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.servlet.HandlerInterceptor;

import com.cw.base.common.model.constants.RestConstant;
import com.cw.base.common.model.dto.base.BaseReqDto;
import com.cw.base.common.model.enums.EnumServiceScene;
import com.cw.base.common.model.util.AppParamUtil;
import com.cw.lang.cache.Cache;
import com.cw.lang.common.enums.EnumBool;
import com.cw.lang.common.exception.BizException;
import com.cw.lang.common.exception.CheckException;
import com.cw.lang.common.framework.config.FrameworkRpcProperties;
import com.cw.lang.common.framework.enums.EnumRpcError;

import lombok.Getter;
import lombok.Setter;

/**
 * 幂等校验过滤器，依赖于{@link RequestHeaderMvcHandlerInterceptor}
 * 把{@link BaseReqDto} 塞到线程上下文
 *
 * @author chenw
 * @version $$Id: IdempotentMvcHandlerInterceptor.java, v 0.1 2018/11/1 10:23 AM chenw Exp $$
 */
@Getter
@Setter
@Order(Ordered.HIGHEST_PRECEDENCE + 2000)
public class IdempotentMvcHandlerInterceptor implements HandlerInterceptor {

    private FrameworkRpcProperties frameworkRpcProperties;
    @Autowired
    private Cache<String,String> cache;

    /** 缓存幂等流水号的业务含义 */
    private static final String IDEM_SERIAL_NO_SCENE = "IdemSerialNo";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (request.getRequestURI()
            .startsWith(RestConstant.BASE_URL_PREFIX)) {
            BaseReqDto baseReqDto = AppParamUtil.getBaseRequest();
            if (baseReqDto == null) {
                throw new BizException(EnumRpcError.BASE_REQUEST_CAN_NOT_BE_NULL.getCode(),
                    EnumRpcError.BASE_REQUEST_CAN_NOT_BE_NULL.getDescription());
            }
            EnumServiceScene serviceScene = baseReqDto.getServiceScene();
            // 查询及异步任务类型的服务场景，不做幂等判断
            if (EnumServiceScene.QUERY.equals(serviceScene) || EnumServiceScene.ASYNC_TASK.equals(serviceScene)) {
                return true;
            }
            String key = IDEM_SERIAL_NO_SCENE + ":" + AppParamUtil.getBaseRequest()
                .getIdemSerialNo();
            if (EnumBool.YES.getCode()
                .equals(cache.get(key))) {
                throw new CheckException(EnumRpcError.IDEMPOTENT_ERROR.getCode(),
                    EnumRpcError.IDEMPOTENT_ERROR.getDescription());
            } else {
                cache.set(key, EnumBool.YES.getCode(), frameworkRpcProperties.getMvc()
                    .getIdempotentExpireTime());
            }
        }
        return true;
    }

}
